﻿using System.IO;
using System.Runtime.Serialization;
using System.Xml;

namespace SBRepository.LinqToSql
{
    /// <summary>
    /// Helper class used to detach Linq to Sql entities from the underlying context.
    /// </summary>
    internal static class Detacher
    {
        /// <summary>
        /// Detaches specified entity from the underlying context.
        /// </summary>
        /// <typeparam name="TEntity">The type of the entity to detach.</typeparam>
        /// <param name="entity">The entity to detach.</param>
        /// <returns>Detached entity.</returns>
        public static TEntity Detach<TEntity>(TEntity entity)
        {
            return Deserialize<TEntity>(Serialize(entity));
        }

        /// <summary>
        /// Serializes specified entity.
        /// </summary>
        /// <typeparam name="TEntity">The type of the entity to serialize.</typeparam>
        /// <param name="entity">The entity to serialize.</param>
        /// <returns>Serialized to the XML entity.</returns>
        private static string Serialize<TEntity>(TEntity entity)
        {
            using (var stringWriter = new StringWriter())
            {
                using (var xmlWriter = XmlWriter.Create(stringWriter))
                {
                    var serializer = new DataContractSerializer(typeof(TEntity));
                    serializer.WriteObject(xmlWriter, entity);
                }
                return stringWriter.ToString();
            }
        }

        /// <summary>
        /// Deserializes specified entity.
        /// </summary>
        /// <typeparam name="TEntity">The type of the entity to deserialize.</typeparam>
        /// <param name="entity">The entity to deserialize.</param>
        /// <returns>Deserialized from the XML entity.</returns>
        private static TEntity Deserialize<TEntity>(string entity)
        {
            using (var stringReader = new StringReader(entity))
            using (var reader = XmlReader.Create(stringReader))
            {
                var serializer = new DataContractSerializer(typeof(TEntity));

                return (TEntity)serializer.ReadObject(reader);
            }
        }
    }
}
